/* do not edit automatically generated by mc from Lists.  */
/* Lists.mod provides an unordered list manipulation package.

Copyright (C) 2001-2023 Free Software Foundation, Inc.
Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.

This file is part of GNU Modula-2.

GNU Modula-2 is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.

GNU Modula-2 is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Modula-2; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#   if !defined (PROC_D)
#      define PROC_D
       typedef void (*PROC_t) (void);
       typedef struct { PROC_t proc; } PROC;
#   endif

#   if !defined (TRUE)
#      define TRUE (1==1)
#   endif

#   if !defined (FALSE)
#      define FALSE (1==0)
#   endif

#include <stddef.h>
#   include "GStorage.h"
#if defined(__cplusplus)
#   undef NULL
#   define NULL 0
#endif
#define _Lists_H
#define _Lists_C

#   include "GStorage.h"

typedef struct SymbolKey_PerformOperation_p SymbolKey_PerformOperation;

#   define MaxNoOfElements 5
typedef struct Lists_list_r Lists_list;

typedef struct Lists__T1_a Lists__T1;

typedef Lists_list *Lists_List;

typedef void (*SymbolKey_PerformOperation_t) (unsigned int);
struct SymbolKey_PerformOperation_p { SymbolKey_PerformOperation_t proc; };

struct Lists__T1_a { unsigned int array[MaxNoOfElements-1+1]; };
struct Lists_list_r {
                      unsigned int NoOfElements;
                      Lists__T1 Elements;
                      Lists_List Next;
                    };


/*
   InitList - creates a new list, l.
*/

extern "C" void Lists_InitList (Lists_List *l);

/*
   KillList - deletes the complete list, l.
*/

extern "C" void Lists_KillList (Lists_List *l);

/*
   PutItemIntoList - places a WORD, c, into list, l.
*/

extern "C" void Lists_PutItemIntoList (Lists_List l, unsigned int c);
extern "C" unsigned int Lists_GetItemFromList (Lists_List l, unsigned int n);

/*
   GetIndexOfList - returns the index for WORD, c, in list, l.
                    If more than one WORD, c, exists the index
                    for the first is returned.
*/

extern "C" unsigned int Lists_GetIndexOfList (Lists_List l, unsigned int c);

/*
   NoOfItemsInList - returns the number of items in list, l.
                     (iterative algorithm of the above).
*/

extern "C" unsigned int Lists_NoOfItemsInList (Lists_List l);

/*
   IncludeItemIntoList - adds a WORD, c, into a list providing
                         the value does not already exist.
*/

extern "C" void Lists_IncludeItemIntoList (Lists_List l, unsigned int c);

/*
   RemoveItemFromList - removes a WORD, c, from a list.
                        It assumes that this value only appears once.
*/

extern "C" void Lists_RemoveItemFromList (Lists_List l, unsigned int c);

/*
   IsItemInList - returns true if a WORD, c, was found in list, l.
*/

extern "C" unsigned int Lists_IsItemInList (Lists_List l, unsigned int c);

/*
   ForeachItemInListDo - calls procedure, P, foreach item in list, l.
*/

extern "C" void Lists_ForeachItemInListDo (Lists_List l, SymbolKey_PerformOperation P);

/*
   DuplicateList - returns a duplicate list derived from, l.
*/

extern "C" Lists_List Lists_DuplicateList (Lists_List l);

/*
   RemoveItem - remove an element at index, i, from the list data type.
*/

static void RemoveItem (Lists_List p, Lists_List l, unsigned int i);


/*
   RemoveItem - remove an element at index, i, from the list data type.
*/

static void RemoveItem (Lists_List p, Lists_List l, unsigned int i)
{
  l->NoOfElements -= 1;
  while (i <= l->NoOfElements)
    {
      l->Elements.array[i-1] = l->Elements.array[i+1-1];
      i += 1;
    }
  if ((l->NoOfElements == 0) && (p != NULL))
    {
      p->Next = l->Next;
      Storage_DEALLOCATE ((void **) &l, sizeof (Lists_list));
    }
}


/*
   InitList - creates a new list, l.
*/

extern "C" void Lists_InitList (Lists_List *l)
{
  Storage_ALLOCATE ((void **) &(*l), sizeof (Lists_list));
  (*l)->NoOfElements = 0;
  (*l)->Next = NULL;
}


/*
   KillList - deletes the complete list, l.
*/

extern "C" void Lists_KillList (Lists_List *l)
{
  if ((*l) != NULL)
    {
      if ((*l)->Next != NULL)
        {
          Lists_KillList (&(*l)->Next);
        }
      Storage_DEALLOCATE ((void **) &(*l), sizeof (Lists_list));
    }
}


/*
   PutItemIntoList - places a WORD, c, into list, l.
*/

extern "C" void Lists_PutItemIntoList (Lists_List l, unsigned int c)
{
  if (l->NoOfElements < MaxNoOfElements)
    {
      l->NoOfElements += 1;
      l->Elements.array[l->NoOfElements-1] = c;
    }
  else if (l->Next != NULL)
    {
      /* avoid dangling else.  */
      Lists_PutItemIntoList (l->Next, c);
    }
  else
    {
      /* avoid dangling else.  */
      Lists_InitList (&l->Next);
      Lists_PutItemIntoList (l->Next, c);
    }
}

extern "C" unsigned int Lists_GetItemFromList (Lists_List l, unsigned int n)
{
  /* iterative solution  */
  while (l != NULL)
    {
      if (n <= l->NoOfElements)
        {
          return l->Elements.array[n-1];
        }
      else
        {
          n -= l->NoOfElements;
        }
      l = l->Next;
    }
  return static_cast<unsigned int> (0);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   GetIndexOfList - returns the index for WORD, c, in list, l.
                    If more than one WORD, c, exists the index
                    for the first is returned.
*/

extern "C" unsigned int Lists_GetIndexOfList (Lists_List l, unsigned int c)
{
  unsigned int i;

  if (l == NULL)
    {
      return 0;
    }
  else
    {
      i = 1;
      while (i <= l->NoOfElements)
        {
          if (l->Elements.array[i-1] == c)
            {
              return i;
            }
          else
            {
              i += 1;
            }
        }
      return l->NoOfElements+(Lists_GetIndexOfList (l->Next, c));
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   NoOfItemsInList - returns the number of items in list, l.
                     (iterative algorithm of the above).
*/

extern "C" unsigned int Lists_NoOfItemsInList (Lists_List l)
{
  unsigned int t;

  if (l == NULL)
    {
      return 0;
    }
  else
    {
      t = 0;
      do {
        t += l->NoOfElements;
        l = l->Next;
      } while (! (l == NULL));
      return t;
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   IncludeItemIntoList - adds a WORD, c, into a list providing
                         the value does not already exist.
*/

extern "C" void Lists_IncludeItemIntoList (Lists_List l, unsigned int c)
{
  if (! (Lists_IsItemInList (l, c)))
    {
      Lists_PutItemIntoList (l, c);
    }
}


/*
   RemoveItemFromList - removes a WORD, c, from a list.
                        It assumes that this value only appears once.
*/

extern "C" void Lists_RemoveItemFromList (Lists_List l, unsigned int c)
{
  Lists_List p;
  unsigned int i;
  unsigned int Found;

  if (l != NULL)
    {
      Found = FALSE;
      p = NULL;
      do {
        i = 1;
        while ((i <= l->NoOfElements) && (l->Elements.array[i-1] != c))
          {
            i += 1;
          }
        if ((i <= l->NoOfElements) && (l->Elements.array[i-1] == c))
          {
            Found = TRUE;
          }
        else
          {
            p = l;
            l = l->Next;
          }
      } while (! ((l == NULL) || Found));
      if (Found)
        {
          RemoveItem (p, l, i);
        }
    }
}


/*
   IsItemInList - returns true if a WORD, c, was found in list, l.
*/

extern "C" unsigned int Lists_IsItemInList (Lists_List l, unsigned int c)
{
  unsigned int i;

  do {
    i = 1;
    while (i <= l->NoOfElements)
      {
        if (l->Elements.array[i-1] == c)
          {
            return TRUE;
          }
        else
          {
            i += 1;
          }
      }
    l = l->Next;
  } while (! (l == NULL));
  return FALSE;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   ForeachItemInListDo - calls procedure, P, foreach item in list, l.
*/

extern "C" void Lists_ForeachItemInListDo (Lists_List l, SymbolKey_PerformOperation P)
{
  unsigned int i;
  unsigned int n;

  n = Lists_NoOfItemsInList (l);
  i = 1;
  while (i <= n)
    {
      (*P.proc) (Lists_GetItemFromList (l, i));
      i += 1;
    }
}


/*
   DuplicateList - returns a duplicate list derived from, l.
*/

extern "C" Lists_List Lists_DuplicateList (Lists_List l)
{
  Lists_List m;
  unsigned int n;
  unsigned int i;

  Lists_InitList (&m);
  n = Lists_NoOfItemsInList (l);
  i = 1;
  while (i <= n)
    {
      Lists_PutItemIntoList (m, Lists_GetItemFromList (l, i));
      i += 1;
    }
  return m;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}

extern "C" void _M2_Lists_init (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[])
{
}

extern "C" void _M2_Lists_fini (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[])
{
}
